package sg.edu.ntu.sce.sands.crypto;

import com.alibaba.excel.EasyExcel;
import it.unisa.dia.gas.jpbc.Element;
import it.unisa.dia.gas.jpbc.Field;
import it.unisa.dia.gas.jpbc.Pairing;
import it.unisa.dia.gas.plaf.jpbc.pairing.PairingFactory;
import sg.edu.ntu.sce.sands.crypto.dcpabe.*;
import sg.edu.ntu.sce.sands.crypto.dcpabe.ac.AccessStructure;
import sg.edu.ntu.sce.sands.crypto.dcpabe.key.PersonalKey;

import java.util.ArrayList;
import java.util.List;

public class Main {
    /**
     * 测试数据的条数
     */
    public static final int COUNT = 10;
    /**
     * 测试文件的大小（字节）
     */
    public static final int TEST_SIZE = 64;
    /**
     * 生成随机字符串的大小（字节）
     */
    public static final int[] FILE_SIZE = new int[]{
            10000000,
            20000000,
            30000000,
            40000000,
            50000000,
            60000000,
            70000000,
            80000000,
            90000000,
    };
    /**
     * 生成随机字符串的大小（字节）
     */
//    public static final int[] FILE_SIZE = new int[]{
//            8,
//            64,
//            512,
//            4096,
//            32768,
//            262144,
//            2097152,
//            16777216,
//            134217728,
//    };
    /**
     * 属性集合
     */
    public static final String[][] ATTR_COUNT = new String[][]{
            {"a", "b", "c", "d"},
            {"a", "b", "c", "d", "e", "f", "g", "h"},
            { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j","k","l"},
            { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j","k","l","m","n","o","p"},
            { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j","k","l","m","n","o","p","q","r","s","t"},
            { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j","k","l","m","n","o","p","q","r","s","t","u","v","w","x"}
    };
    /**
     * 策略集合
     */
    public static final String[] POLICY = new String[]{
            "and a d b c",
            "and a d b c e f g h",
            "and a d b c e f g h i j k l",
            "and a d b c e f g h i j k l m n o p",
            "and a d b c e f g h i j k l m n o p q r s t",
            "and a d b c e f g h i j k l m n o p q r s t u v w x",
    };

    public static void main(String[] args) {
        /**
         * 测试Kmas的生成时间
         */
        testKmasWithFileSize();
        /**
         * 测试整体流程的时间
         * cpabe加密Kmas
         */
        testKmasCpabeWithFileSize();

//        // 1 cpabe(h) benc(h)
        testCpabeBencWithFileSize();
//        // 总 enc(m) h(benc(h))
        testBencHashWithFileSize();
    }
    public static void testBencHashWithFileSize(){
        List<List<Long>> timeDiffList = new ArrayList<>();
        for (int k = 0; k < COUNT; k++) {
            System.out.println("进度："+k);
            List<Long> timeDiffArr = new ArrayList<>();
            for (int i = 0; i < FILE_SIZE.length; i++) {
                long startTime = System.currentTimeMillis();

                GlobalParameters gp = DCPABE.globalSetup(160);
                PublicKeys publicKeys = new PublicKeys();

                AuthorityKeys authority0 = DCPABE.authoritySetup("a1", gp, "a", "b", "c", "d");
                // 授权
                publicKeys.subscribeAuthority(authority0.getPublicKeys());

                AccessStructure as = AccessStructure.buildFromPolicy("and a or d and b c");
                // 密钥生成阶段
                PersonalKeys pkeys = new PersonalKeys("user");
                PersonalKey k_user_a = DCPABE.keyGen("user", "a", authority0.getSecretKeys().get("a"), gp);
                PersonalKey k_user_d = DCPABE.keyGen("user", "d", authority0.getSecretKeys().get("d"), gp);
                pkeys.addKey(k_user_a);
                pkeys.addKey(k_user_d);
                // 生成待加密消息
                Message message = DCPABE.generateRandomMessageWithHash(FILE_SIZE[i], gp);

                // 加密阶段
                Ciphertext ct = DCPABE.encrypt(message, as, gp, publicKeys);
                // 解秘阶段
                Message dmessage = DCPABE.decrypt(ct, pkeys, gp);

                String str = Kmas.getRandomString(FILE_SIZE[i]);
                Kmas.BEnc("ABE",str);
                Kmas.getHash(Kmas.BEnc("ABE",Kmas.getHash(str)));
                long endTime = System.currentTimeMillis();
                timeDiffArr.add(endTime - startTime);
            }
            timeDiffList.add(timeDiffArr);
        }
        EasyExcel.write(".\\O2_testCpabeWithFileSize.xls").head(getHeadList()).sheet("timeDiff").doWrite(timeDiffList);

    }
    public static void  testCpabeBencWithFileSize(){
        List<List<Long>> timeDiffList = new ArrayList<>();
        for (int k = 0; k < COUNT; k++) {
            System.out.println("进度："+k);
            List<Long> timeDiffArr = new ArrayList<>();
            for (int i = 0; i < FILE_SIZE.length; i++) {
                long startTime = System.currentTimeMillis();
                GlobalParameters gp = DCPABE.globalSetup(160);
                PublicKeys publicKeys = new PublicKeys();

                AuthorityKeys authority0 = DCPABE.authoritySetup("a1", gp, "a", "b", "c", "d");
                // 授权
                publicKeys.subscribeAuthority(authority0.getPublicKeys());

                AccessStructure as = AccessStructure.buildFromPolicy("and a or d and b c");
                // 密钥生成阶段
                PersonalKeys pkeys = new PersonalKeys("user");
                PersonalKey k_user_a = DCPABE.keyGen("user", "a", authority0.getSecretKeys().get("a"), gp);
                PersonalKey k_user_d = DCPABE.keyGen("user", "d", authority0.getSecretKeys().get("d"), gp);
                pkeys.addKey(k_user_a);
                pkeys.addKey(k_user_d);
                // 生成待加密消息
                Message message = DCPABE.generateRandomMessageWithHash(FILE_SIZE[i], gp);

                // 加密阶段
                Ciphertext ct = DCPABE.encrypt(message, as, gp, publicKeys);
                // 解秘阶段
                Message dmessage = DCPABE.decrypt(ct, pkeys, gp);

                long endTime = System.currentTimeMillis();
                timeDiffArr.add(endTime - startTime);
            }
            timeDiffList.add(timeDiffArr);
        }
        EasyExcel.write(".\\O1_testCpabeWithFileSize.xls").head(getHeadList()).sheet("timeDiff").doWrite(timeDiffList);

    }
    public static void testKmasWithFileSize() {
        List<List<Long>> timeDiffList = new ArrayList<>();
        for (int k = 0; k < COUNT; k++) {
            System.out.println("进度："+k);
            List<Long> timeDiffArr = new ArrayList<>();
            for (int i = 0; i < FILE_SIZE.length; i++) {
                long startTime = System.currentTimeMillis();
                // 加密阶段
                String kmas = Kmas.getKmas(FILE_SIZE[i]);
                long endTime = System.currentTimeMillis();
                timeDiffArr.add(endTime - startTime);
            }
            timeDiffList.add(timeDiffArr);
        }
        EasyExcel.write(".\\L1_testKmasWithFileSize.xls").head(getHeadList()).sheet("timeDiff").doWrite(timeDiffList);
    }
    public static void testKmasCpabeWithFileSize() {
        List<List<Long>> timeDiffList = new ArrayList<>();
        for (int k = 0; k < COUNT; k++) {
            System.out.println("进度："+k);
            List<Long> timeDiffArr = new ArrayList<>();
            for (int i = 0; i < FILE_SIZE.length; i++) {
                long startTime = System.currentTimeMillis();
                GlobalParameters gp = DCPABE.globalSetup(160);
                PublicKeys publicKeys = new PublicKeys();

                AuthorityKeys authority0 = DCPABE.authoritySetup("a1", gp, "a", "b", "c", "d");
                // 授权
                publicKeys.subscribeAuthority(authority0.getPublicKeys());

                AccessStructure as = AccessStructure.buildFromPolicy("and a or d and b c");
                // 密钥生成阶段
                PersonalKeys pkeys = new PersonalKeys("user");
                PersonalKey k_user_a = DCPABE.keyGen("user", "a", authority0.getSecretKeys().get("a"), gp);
                PersonalKey k_user_d = DCPABE.keyGen("user", "d", authority0.getSecretKeys().get("d"), gp);
                pkeys.addKey(k_user_a);
                pkeys.addKey(k_user_d);

                // 加密阶段
                String kmas = Kmas.getKmas(FILE_SIZE[i]);
                // 生成待加密消息
                Message message = DCPABE.generateRandomMessage(kmas, gp);
                Ciphertext ct = DCPABE.encrypt(message, as, gp, publicKeys);

                // 解秘阶段
                Message dmessage = DCPABE.decrypt(ct, pkeys, gp);
                // 生成验证标签
//                Element tr = getLabel(kmas,gp);
                long endTime = System.currentTimeMillis();
                timeDiffArr.add(endTime - startTime);
            }
            timeDiffList.add(timeDiffArr);
        }
        EasyExcel.write(".\\L总_testKmasCpabeWithFileSize.xls").head(getHeadList()).sheet("timeDiff").doWrite(timeDiffList);
    }
    public static void testAttrCount() {
        GlobalParameters gp = DCPABE.globalSetup(160);
        PublicKeys publicKeys = new PublicKeys();

        List<List<Long>> keyList = new ArrayList<>();
        List<List<Long>> encryptList = new ArrayList<>();
        List<List<Long>> decryptList = new ArrayList<>();
        for (int k = 0; k < COUNT; k++) {
            System.out.println("次数："+k);
            List<Long> keyArr = new ArrayList<>();
            List<Long> encryptArr = new ArrayList<>();
            List<Long> decryptArr = new ArrayList<>();

            for (int i = 0; i < POLICY.length; i++) {
            AuthorityKeys authority0 = DCPABE.authoritySetup("a1", gp, ATTR_COUNT[i]);
            publicKeys.subscribeAuthority(authority0.getPublicKeys());
            AccessStructure as = AccessStructure.buildFromPolicy(POLICY[i]);
                // 密钥生成阶段
                long l5 = System.currentTimeMillis();
                PersonalKeys pkeys = new PersonalKeys("user");
//                PersonalKey k_user_a = DCPABE.keyGen("user", "a", authority0.getSecretKeys().get("a"), gp);
//                PersonalKey k_user_d = DCPABE.keyGen("user", "d", authority0.getSecretKeys().get("d"), gp);
//                pkeys.addKey(k_user_a);
//                pkeys.addKey(k_user_d);
                for (int j = 0; j < ATTR_COUNT[i].length; j++) {
                    pkeys.addKey(DCPABE.keyGen("user", ATTR_COUNT[i][j], authority0.getSecretKeys().get(ATTR_COUNT[i][j]), gp));
                }

                long l6 = System.currentTimeMillis();
                keyArr.add(l6 - l5);

                // 加密阶段
                long l1 = System.currentTimeMillis();
                Message message = DCPABE.generateRandomMessage(TEST_SIZE, gp);
                Ciphertext ct = DCPABE.encrypt(message, as, gp, publicKeys);
                long l2 = System.currentTimeMillis();
                encryptArr.add(l2 - l1);

                // 解秘阶段
                long l3 = System.currentTimeMillis();
                Message dmessage = DCPABE.decrypt(ct, pkeys, gp);
                long l4 = System.currentTimeMillis();
                decryptArr.add(l4 - l3);
            }
            keyList.add(keyArr);
            encryptList.add(encryptArr);
            decryptList.add(decryptArr);
        }
        EasyExcel.write(".\\keyGen_attr.xls").head(getHeadListWithAttr()).sheet("密钥生成").doWrite(keyList);
        EasyExcel.write(".\\encrypt_attr.xls").head(getHeadListWithAttr()).sheet("加密").doWrite(encryptList);
        EasyExcel.write(".\\decrypt_attr.xls").head(getHeadListWithAttr()).sheet("解密").doWrite(decryptList);
    }

    public static void testCpabeWithFileSize() {
        List<List<Long>> timeDiffList = new ArrayList<>();
        for (int k = 0; k < COUNT; k++) {
            System.out.println("进度："+k);
            List<Long> timeDiffArr = new ArrayList<>();
            for (int i = 0; i < FILE_SIZE.length; i++) {
                long startTime = System.currentTimeMillis();
                GlobalParameters gp = DCPABE.globalSetup(160);
                PublicKeys publicKeys = new PublicKeys();

                AuthorityKeys authority0 = DCPABE.authoritySetup("a1", gp, "a", "b", "c", "d");
                // 授权
                publicKeys.subscribeAuthority(authority0.getPublicKeys());

                AccessStructure as = AccessStructure.buildFromPolicy("and a or d and b c");
                // 密钥生成阶段
                PersonalKeys pkeys = new PersonalKeys("user");
                PersonalKey k_user_a = DCPABE.keyGen("user", "a", authority0.getSecretKeys().get("a"), gp);
                PersonalKey k_user_d = DCPABE.keyGen("user", "d", authority0.getSecretKeys().get("d"), gp);
                pkeys.addKey(k_user_a);
                pkeys.addKey(k_user_d);
                // 生成待加密消息
                Message message = DCPABE.generateRandomMessage(FILE_SIZE[i], gp);

                // 加密阶段
                Ciphertext ct = DCPABE.encrypt(message, as, gp, publicKeys);
                // 解秘阶段
                Message dmessage = DCPABE.decrypt(ct, pkeys, gp);
                long endTime = System.currentTimeMillis();
                timeDiffArr.add(endTime - startTime);
            }
            timeDiffList.add(timeDiffArr);
        }
        EasyExcel.write(".\\timeDiff_testCpabeWithFileSize.xls").head(getHeadList()).sheet("timeDiff").doWrite(timeDiffList);
    }
    public static Element getLabel(String str, GlobalParameters GP){
        Pairing pairing = PairingFactory.getPairing(GP.getPairingParameters());
        // 生成群
        Field G1 = pairing.getG1();
        Field Zr = pairing.getZr();

        Element g = G1.newRandomElement();
        Element a = Zr.newRandomElement();
        Element b = Zr.newRandomElement();
//        b.mul(Integer.getInteger(str));
        // g^a
        Element g_a = g.duplicate().powZn(a);
        Element g_b = g.duplicate().powZn(b);

        Element egg_ab = pairing.pairing(g_a,g_b);
        return egg_ab;
    }
    public static List<List<String>> getHeadListWithAttr() {
        List<String> result1 = new ArrayList<>();
        result1.add("4属性");
        List<String> result2 = new ArrayList<>();
        result2.add("8属性");
        List<String> result3 = new ArrayList<>();
        result3.add("12属性");
        List<String> result4 = new ArrayList<>();
        result4.add("16属性");
        List<String> result5 = new ArrayList<>();
        result5.add("20属性");
        List<String> result6 = new ArrayList<>();
        result6.add("24属性");
        List<List<String>> headList = new ArrayList<>();
        headList.add(result1);
        headList.add(result2);
        headList.add(result3);
        headList.add(result4);
        headList.add(result5);
        headList.add(result6);
        return headList;
    }
    /**
     * 生成表头
     *
     * @return
     */
    public static List<List<String>> getHeadList() {
        List<String> result1 = new ArrayList<>();
        result1.add("8字节");
        List<String> result2 = new ArrayList<>();
        result2.add("64字节");
        List<String> result3 = new ArrayList<>();
        result3.add("512字节");
        List<String> result4 = new ArrayList<>();
        result4.add("4096字节");
        List<String> result5 = new ArrayList<>();
        result5.add("32768字节");
        List<String> result6 = new ArrayList<>();
        result6.add("262144字节");
        List<String> result7 = new ArrayList<>();
        result7.add("2097152字节");
        List<String> result8 = new ArrayList<>();
        result8.add("16777216字节");
        List<String> result9 = new ArrayList<>();
        result9.add("134217728字节");

        List<List<String>> headList = new ArrayList<>();
        headList.add(result1);
        headList.add(result2);
        headList.add(result3);
        headList.add(result4);
        headList.add(result5);
        headList.add(result6);
        headList.add(result7);
        headList.add(result8);
        headList.add(result9);
        return headList;
    }
}
